#include "mini_string.hpp"
#include "stringAPI.hpp"
namespace king
{
    // 构造、下标访问
    void test_string1()
    {
        // 构造
        string s1("hello world");
        string s2; // 若使用无参构造1.0无法输出
        // c_str
        cout << s1.c_str() << endl;
        cout << s2.c_str() << endl;
        // 下标访问
        for (size_t i = 0; i < s1.size(); ++i)
        {
            cout << s1[i] << " ";
        }
        cout << endl;
        // 下标访问const
        for (size_t i = 0; i < s1.size(); ++i)
        {
            s1[i]++;
            cout << s1[i] << " ";
        }
    }

    // 迭代器
    void test_string2()
    {
        // 迭代器访问
        string s1("hello world");
        string::iterator it = s1.begin();
        while (it != s1.end())
        {
            *it += 1;
            cout << *it << " ";
            ++it;
        }
        cout << endl;

        // 迭代器--范围for
        for (auto ch : s1)
        {
            cout << ch << " ";
        }
        cout << endl;
    }

    // 拷贝构造
    void test_string3()
    {
        string s1("hello world");
        string s2(s1);
        cout << s1.c_str() << endl;
        cout << s2.c_str() << endl;

        s2[0] = 'x';
        cout << s1.c_str() << endl;
        cout << s2.c_str() << endl;

        string s3("111111111111111111111111111111");

        s1 = s3;
        // 默认的赋值存在的问题：
        // 1.s1._str指向空间的地址丢失
        // 2.对同一块空间析构两次

        cout << s1.c_str() << endl;
        cout << s3.c_str() << endl;

        s1 = s1;
        cout << s1.c_str() << endl;
        cout << s3.c_str() << endl;
    }

    // 两个swap函数

    // 增加字符
    void test_string5()
    {
        string s1("hello");
        cout << s1.c_str() << endl;
        s1.push_back('x');
        cout << s1.c_str() << endl;
        cout << s1.capacity() << endl;

        s1 += 'y';
        s1 += 'z';
        s1 += 'z';
        s1 += 'z';
        s1 += 'z';
        s1 += 'z';
        s1 += 'z';
        cout << s1.c_str() << endl;
        cout << s1.capacity() << endl;
    }

    // 增加字符串
    void test_string6()
    {
        string s1("hello");
        cout << s1.c_str() << endl;
        s1 += ' ';
        s1.append("world");
        s1 += "bit hello";
        cout << s1.c_str() << endl;
    }

    // 插入字符、字符串
    void test_string7()
    {
        string s1("hello");
        cout << s1.c_str() << endl;

        s1.insert(5, '#');
        cout << s1.c_str() << endl;

        s1.insert(0, '#');
        cout << s1.c_str() << endl;

        s1.insert(2, "world");
        cout << s1.c_str() << endl;

        s1.insert(0, "world ");
        cout << s1.c_str() << endl;
    }

    // 删除字符、字符串
    void test_string8()
    {
        string s1("hello");
        s1.erase(1, 10);
        cout << s1.c_str() << endl;

        string s2("hello");
        s2.erase(1);
        cout << s2.c_str() << endl;

        string s3("hello");
        s3.erase(1, 2);
        cout << s3.c_str() << endl;
    }

    // 流插入、流提取
    void test_string9()
    {
        string s1("hello");
        cout << s1 << endl;
        cout << s1.c_str() << endl;
        s1 += '\0';
        s1 += "world";
        cout << s1 << endl;
        cout << s1.c_str() << endl;

        string s3, s4;
        cin >> s3 >> s4;
        cout << s3 << s4 << endl;
    }

    // find、substr
    void DealUrl(const string &url)
    {
        size_t pos1 = url.find("://");
        if (pos1 == string::npos)
        {
            cout << "非法url" << endl;
            return;
        }
        string protocol = url.substr(0, pos1);
        // 从网址首部取pos1个字符作为子串
        cout << protocol << endl;

        size_t pos2 = url.find('/', pos1 + 3);
        if (pos2 == string::npos)
        {
            cout << "非法url" << endl;
            return;
        }
        string domain = url.substr(pos1 + 3, pos2 - pos1 - 3);
        cout << domain << endl;

        string uri = url.substr(pos2 + 1);
        cout << uri << endl
             << endl;
    }
    void test_string10()
    {
        string url1 = "https://cplusplus.com/reference/string/string/";
        string url2 = "ftp://ftp.cs.umd.edu/pub/skipLists/skiplists.pdf";

        DealUrl(url1);
        DealUrl(url2);
    }

    // resize函数：开空间 + 初始化
    void test_string11()
    {
        string s1;
        s1.resize(20);

        string s2("hello");
        s2.resize(20, 'x');

        s2.resize(10);
    }

    // vs对于string类的优化
    void test_string12()
    {
        std::string s0;
        std::string s1("111111");
        std::string s2("11111111111111111111111111111111111111111");
        cout << sizeof(s0) << endl; // 40
        cout << sizeof(s1) << endl; // 40
        cout << sizeof(s2) << endl; // 40

        // 理论上：sizeof(s) == 12
        // 实  际：string还有第4个成员变量
        // 不同vs版本不同 此VS2022下：char _buff[28]
        //_size <  28 :字符串存放在_buff数组中
        //_size >= 28 :            _str指向的堆空间上
    }
    void test_string13()
    {
        cout << "1. 测试默认构造：" << endl;
        string s1("Hello");
        s1.print();
        cout << endl;
    
        cout << "2. 测试拷贝构造：" << endl;
        string s2(s1);
        //string s2 = s1;
        s2.print();
        cout << endl;
    
        cout << "3.1 测试移动构造：string s3 = s1 + s2;" << endl;
        // string s3 = std::move(s1 + s2);
        string s3 = s1 + s2;
        s3.print();
        cout << endl;
    
        cout << "3.2 测试移动构造：string s3 = std::move(s1);" << endl;
        s3 = std::move(s1);
        s3.print();
        cout << endl;

        cout << "4. 测试拷贝赋值：" << endl;
        string s4("World");
        s4 = s3;
        s4.print();
        cout << endl;
    
        cout << "5. 测试移动赋值：" << endl;
        string s5("C++");
        s5 = std::move(s4);
        s5.print();
        cout << endl;
    }
}

void test_string4()
{
    string s1("hello world");
    string s2("xxxxxxx");

    // s1.swap(s2);
    // 模拟实现string类的成员函数：void swap(string& t)
    //==>   原string类的成员函数：void std::string::swap(string & str);
    // 作用：交换类的成员变量（_str交换地址）
    s1.swap(s2);

    // 全局域的swap函数：
    /*
    template <class T>
    void std::swap(T & a, T & b);
    {
        T c(a);
        a = b;
        b = a;
    }
    */
    // 作用：经历了拷贝构造+赋值运算 a b 的_str指向空间的地址均被更新

    std::swap(s1, s2);
    ::swap(s1, s2);
}

void test_c_ptr()
{
    int a[3][4] = {0};

    printf("%zu\n", sizeof(a));            // 48 - 整个二维数组的大小(3*4*4=48)
    printf("%zu\n", sizeof(a[0][0]));      // 4  - 单个int元素的大小
    printf("%zu\n", sizeof(a[0]));         // 16 - 第一行数组的大小(int[4])
    printf("%zu\n", sizeof(a[0] + 1));     // 8  - 第一行第二个元素的地址大小(指针大小，64位系统)
    printf("%zu\n", sizeof(*(a[0] + 1)));  // 4  - 第一行第二个元素的值的大小(int)
    printf("%zu\n", sizeof(a + 1));        // 8  - 第二行起始地址的指针大小
    printf("%zu\n", sizeof(*(a + 1)));     // 16 - 第二行数组的大小(int[4])
    printf("%zu\n", sizeof(&a[0] + 1));    // 8  - 第二行起始地址的指针大小
    printf("%zu\n", sizeof(*(&a[0] + 1))); // 16 - 第二行数组的大小(int[4])
    printf("%zu\n", sizeof(*a));           // 16 - 第一行数组的大小(int[4])
    printf("%zu\n", sizeof(a[3]));         // 16 - 类型大小计算，不实际访问内存(int[4])
}

void test_strtok()
{
    char a[] = "aaa#bbb@ccc", t[30] = {0};
    char *s = const_cast<char*>("#@");
    char *p = NULL;
    strcpy(t, a);
    for (p = my_strtok(t, s); p != NULL; p = my_strtok(NULL, s))
        printf("%s\n", p);
}
int main()
{
    king::test_string13();

    return 0;
}